package com.imooc.article.controller;

import com.imooc.api.config.RabbitMQConfig;
import com.imooc.api.controller.article.ArticleControllerApi;
import com.imooc.api.controller.user.BaseControllerApi;
import com.imooc.article.service.ArticleService;
import com.imooc.enums.ArticleCoverType;
import com.imooc.enums.ArticleReviewStatus;
import com.imooc.enums.YesOrNo;
import com.imooc.exception.GraceException;
import com.imooc.grance.result.GraceJsonResult;
import com.imooc.grance.result.ResponseStatusEnum;
import com.imooc.pojo.Category;
import com.imooc.pojo.bo.NewArticleBO;
import com.imooc.pojo.vo.ArticleDetaiVO;
import com.imooc.utils.JsonUtils;
import com.imooc.utils.PagedGridResult;
import com.mongodb.client.gridfs.GridFSBucket;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @auther Levi
 * @Date: 2021/03/22/16:38
 * @Description:
 */
@RestController
public class ArticleController extends BaseControllerApi implements ArticleControllerApi {

    @Value("${freemarker.html.path}")
    private String htmlpath;
    @Autowired
    private ArticleService articleService;
    @Autowired
    private GridFSBucket gridFSBucket;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public GraceJsonResult createArticle(@Valid NewArticleBO newArticleBO) {
        //2.如果含有单图，则需要上传一个文章封面,没有的话传一个空字符串
        if (newArticleBO.getArticleType().equals(ArticleCoverType.ONE_IMAGE)) {
            if (newArticleBO.getArticleCover() == null) {
                return GraceJsonResult.errorCustom(ResponseStatusEnum.ARTICLE_COVER_NOT_EXIST_ERROR);
            }
        } else if (newArticleBO.getArticleType().equals(ArticleCoverType.WORDS)) {
            newArticleBO.setArticleCover("");
        }
        Category category = null;
        String redisCats = redis.get(REDIS_ALL_CATEGORY);
        List<Category> categoryList = JsonUtils.jsonToList(redisCats, Category.class);
        for (Category c : categoryList) {
            if (c.getId().equals(newArticleBO.getCategoryId())) {
                category = c;
                break;
            }
        }
        if (category == null) {
            return GraceJsonResult.errorCustom(ResponseStatusEnum.ARTICLE_CATEGORY_NOT_EXIST_ERROR);
        }

        System.out.println(newArticleBO.toString());
        articleService.insert(newArticleBO);

        return GraceJsonResult.ok();
    }

    @Override
    public GraceJsonResult queryMyList(String userId,
                                       Integer status,
                                       Date startDate,
                                       Date endDate,
                                       Integer page,
                                       Integer pageSize,
                                       String keyword) {
        if (page == null) {
            page = COMMON_PAGE;
        }
        if (pageSize == null) {
            pageSize = COMMON_PAGE_SIZE;
        }
        PagedGridResult pagedGridResult = articleService.articleList(userId,
                                        status,
                                        startDate,
                                        endDate,
                                        page,
                                        pageSize,
                                        keyword);
        return GraceJsonResult.ok(pagedGridResult);
    }

    @Override
    public GraceJsonResult queryAllList(Integer status,
                                        Integer page,
                                        Integer pageSize) {
        if (page == null) {
            page = COMMON_PAGE;
        }
        if (pageSize == null) {
            pageSize = COMMON_PAGE_SIZE;
        }
        PagedGridResult all = articleService.findAll(status, page, pageSize);
        return GraceJsonResult.ok(all);
    }

    @Override
    public GraceJsonResult doReview(String articleId, Integer passOrNot) {
        if (StringUtils.isBlank(articleId)) {
            GraceException.display(ResponseStatusEnum.ARTICLE_REVIEW_ERROR);
        }
        Integer status = null;
        if (passOrNot.equals(YesOrNo.YES.type)) {
            status = ArticleReviewStatus.SUCCESS.type;
        } else if (passOrNot.equals(YesOrNo.NO.type)){
            status = ArticleReviewStatus.FAILED.type;
        }else{
            return GraceJsonResult.errorCustom(ResponseStatusEnum.ARTICLE_REVIEW_ERROR);
        }
        //根据审核结果修改文章的状态
        articleService.updatearticleStatus(articleId, status);
        //1.如果文章审核通过则生成静态页面
        if (status.equals(ArticleReviewStatus.SUCCESS.type)) {
            //2.远程调用获得文章的详情

            try {
                //3.生成静态html文件,存入GridFs中，返回的是GridFS里面的id
                String mongoFileId = createArticleHtmlToGridFS(articleId);
                //4.把生成的GridFS的id放进article表里面进行关联
                articleService.updateArticleToGridFs(articleId, mongoFileId);

                //使用MQ发送一条生成html文件的消息
                rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_ARTICLE,
                        "article.createHtml.do",
                        articleId+","+mongoFileId);

                //5.远程调用，从指定位置下载html文件
                //doDownloadArticleHtml(articleId, mongoFileId);
                //使用MQ发送消息，通知消费者进行监听并且进行下载
                doDownloadArticleHtmlByMQ(articleId, mongoFileId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return GraceJsonResult.ok();
    }

    @Override
    public GraceJsonResult delete(String articleId, String userId) {
        articleService.deleteArticle(articleId, userId);

        //调用该方法删除静态html
        deleteGridFSAndHtml(articleId);
        return GraceJsonResult.ok();
    }

    @Override
    public GraceJsonResult withdraw(String articleId, String userId) {
        articleService.withdrawArticle(articleId, userId);
//        //文章删除之后调用该方法删除article中的一条记录和GridFs中的记录
//        articleService.delte(articleId);
        //调用该方法删除静态html
//        deleteGridFSAndHtml(articleId);
        deleteGridFSAndHtmlByMQ(articleId);
        return GraceJsonResult.ok();
    }

    /**
     * 单独一个方法   生成静态页面上传到GridFs中
     * @param articleId
     * @return
     * @throws Exception
     */
    private String createArticleHtmlToGridFS(String articleId) throws Exception{
        //1.配置freemarker基本环境
        Configuration cfg = new Configuration(Configuration.getVersion());
        //获得resource的路径
        String classpath = this.getClass().getResource("/").getPath();
        //设置ftl模板存放的路径，在classpath：/templates下面
        cfg.setDirectoryForTemplateLoading(new File(classpath + "templates"));
        System.out.println(htmlpath);
        System.out.println(classpath + "/templates");
        //2.获得现有的ftl模板
        Template cfgTemplate = cfg.getTemplate("detail.ftl", "utf-8");
        //3.获得动态数据
        ArticleDetaiVO articleDetail = getArticleDetail(articleId);
        Map<String, Object> map = new HashMap<>();

        map.put("articleDetail", articleDetail);
        //4.融合动态数据和ftl
//        File filepath = new File(htmlpath);
//        if (!filepath.exists()) {
//            filepath.mkdirs();
//        }
//        File file = new File(htmlpath+File.separator+articleId+".html");
//        Writer out = new FileWriter(file);
//        cfgTemplate.process(map, out);
//        out.close();
        String htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(cfgTemplate, map);
        InputStream inputStream = IOUtils.toInputStream(htmlString);
        ObjectId objectId = gridFSBucket.uploadFromStream(articleId + ".html", inputStream);
        inputStream.close();
        return objectId.toString();
    }

    private ArticleDetaiVO getArticleDetail(String articleId) {
        String url =
                "http://www.imoocnews.com:8001/portal/article/detail?articleId=" + articleId;
        ResponseEntity<GraceJsonResult> entityResult =
                restTemplate.getForEntity(url, GraceJsonResult.class);
        GraceJsonResult body = entityResult.getBody();
        ArticleDetaiVO articleDetaiVO = null;

        if (body.getStatus() == 200) {
            String articleDetail = JsonUtils.objectToJson(body.getData());
            articleDetaiVO = JsonUtils.jsonToPojo(articleDetail, ArticleDetaiVO.class);
//            System.out.println("userInfoVOList: "+userInfoVOList.toString());
        }
        return articleDetaiVO;
    }

    /**
     * 用户删除或者撤回文章之后，远程调用article-html中的方法，删除GridFS里面的文件和对应的html文件
     * @param articleId
     */
    private void deleteGridFSAndHtml(String articleId) {
        String url = "http://html.imoocnews.com:8002/article/html/deleteHtml?articleId="
                + articleId;
        ResponseEntity<Integer> responseEntity = restTemplate.getForEntity(url, Integer.class);
        Integer body = responseEntity.getBody();
        if (!body.equals(HttpStatus.OK.value())) {
            GraceException.display(ResponseStatusEnum.ARTICLE_DELETE_ERROR);
        }
    }

    /**
     * 使用MQ发送一条消息，让消费者监听并且进行消费，删除GridFS和静态html文件
     * @param articleId
     */
    private void deleteGridFSAndHtmlByMQ(String articleId) {
       rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_ARTICLE,
                                   "article.delete.do",
                                     articleId);
    }

    /**
     * rest方式远程亲自调用下载方法下载html文件
     * @param articleId
     * @param mongoFileId
     */
    public void doDownloadArticleHtml(String articleId,String mongoFileId) {
        String url = "http://html.imoocnews.com:8002/article/html/download?articleId=" +
                articleId
                + "&articleMongoId=" + mongoFileId;
        ResponseEntity<Integer> responseEntity = restTemplate.getForEntity(url, Integer.class);
        Integer statusCode = responseEntity.getBody();
        if (!statusCode.equals(HttpStatus.OK.value())) {
            GraceException.display(ResponseStatusEnum.ARTICLE_REVIEW_ERROR);
        }
    }

    /**
     * 使用RabbitMQ创建一个消息,不用再亲自调用下载的方法了，只要通知，消费者收到通知之后就会自己进行下载
     * @param articleId
     * @param mongoFileId
     */
    public void doDownloadArticleHtmlByMQ(String articleId, String mongoFileId) {
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.EXCHANGE_ARTICLE,
                "article.download.do",
                articleId+","+mongoFileId);

    }
}